﻿using System.Reflection;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection.Emit;
using System.Threading.Tasks;
using System.Resources;

namespace Validate.Net.Core
{
    /// <summary>
    /// 提供数据校验能力
    /// <para>需要校验的类需要实现此接口</para>
    /// </summary>
    public interface IVerify
    {

    }

    /// <summary>
    /// 单次校验结果
    /// <para>属性的每一个校验结果就是一个单独的 <see cref="CheckedResult"/></para>
    /// </summary>
    public class CheckedResult
    {
        /// <summary>
        /// 校验未通过的属性
        /// </summary>
        public PropertyInfo Property { get; set; }
        /// <summary>
        /// 校验未通过的提示语
        /// </summary>
        public string Prompts { get; set; }
    }

    /// <summary>
    /// 合并校验结果
    /// <para>会对同一个属性的所有校验未通过的结果进行合并</para>
    /// </summary>
    public class CheckedResults
    {
        /// <summary>
        /// 校验未通过的属性
        /// </summary>
        public PropertyInfo Property { get; set; }
        /// <summary>
        /// 所有校验未通过的提示语
        /// </summary>
        public IEnumerable<string> Prompts { get; set; }
    }

    /// <summary>
    /// 校验扩展方法
    /// </summary>
    public static class ValidateExtensions
    {
        private static readonly CustomPrompts prompts = new CustomPrompts();

        /// <summary>
        /// 对 对象<paramref name="t"/> 进行校验，每当有未通过的校验就会返回结果。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t">待校验的对象</param>
        /// <returns>校验未通过的结果</returns>
        public static IEnumerable<CheckedResult> Check<T>(this T t) where T : IVerify
        {
            var type = t.GetType();
            var properties = type.GetProperties();
            foreach (var property in properties)
            {
                var attributes = property.GetCustomAttributes<ValidateBaseAttribute>();
                var value = property.GetValue(t);
                foreach (var attribute in attributes)
                {
                    if (!attribute.OnCheck(value))
                    {
                        var propmpts = attribute.InternalPrompts ?? prompts.Get(attribute.GetType()) ?? attribute.Prompts;
                        yield return new CheckedResult() { Property = property, Prompts = propmpts };
                    }
                }
            }
        }

        /// <summary>
        /// 对 <paramref name="t"/> 进行校验，当所有校验完成时返回结果。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t">待校验的对象</param>
        /// <param name="results">所有校验未通过的结果</param>
        /// <returns>所有校验都通过时返回 <see langword="true"/>，否则返回 <see langword="true"/></returns>
        /// <seealso>此方法的耗时非常短，几乎可以忽略，不应该使用 <see cref="Task"/></seealso>
        public static bool Check<T>(this T t, out IList<CheckedResults> results) where T : IVerify
        {
            bool @checked = true;
            results = new List<CheckedResults>();
            var type = t.GetType();
            var properties = type.GetProperties();
            foreach (var property in properties)
            {
                var attributes = property.GetCustomAttributes<ValidateBaseAttribute>();
                var value = property.GetValue(t);
                var _propmpts = new List<string>();
                foreach (var attribute in attributes)
                {
                    if (!attribute.OnCheck(value))
                    {
                        @checked = false;
                        var propmpts = attribute.InternalPrompts ?? prompts.Get(attribute.GetType()) ?? attribute.Prompts;
                        _propmpts.Add(propmpts);
                    }
                }
                if (_propmpts.Count > 0)
                { results.Add(new CheckedResults() { Property = property, Prompts = _propmpts }); }
            }
            return @checked;
        }
    }
}
